Skip to content

Update rust SDK to use new Hegel protocol#1

Merged
DRMacIver merged 23 commits intomainfrom
DRMacIver/new-protocol
Feb 6, 2026
Merged

Update rust SDK to use new Hegel protocol#1
DRMacIver merged 23 commits intomainfrom
DRMacIver/new-protocol

Conversation

@DRMacIver
Copy link
Copy Markdown
Member

This is the SDK-side change from hegeldev/hegel-core#1

This is even more Claude-written than the Python one and requires correspondingly more care. I got the Python SDK to the point where I was happy with it, and then asked Claude to go wild on the Rust one. Will similarly prereview.

@DRMacIver DRMacIver force-pushed the DRMacIver/new-protocol branch 2 times, most recently from bae7d0b to 69bd000 Compare February 3, 2026 11:18
DRMacIver and others added 11 commits February 5, 2026 14:10
- Add protocol.rs with binary packet format (header + CRC32 + CBOR payload)
- Update embedded.rs to use new protocol with version negotiation
- Add MAPPED label for .map() transformations
- Make embedded and protocol modules pub(crate)
- Fix panic info being consumed twice in embedded.rs
- Add crc32fast and ciborium dependencies

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Auto-generated by claude-reliability plugin.
Auto-generated by claude-reliability plugin.
- SDK now connects as client (hegeld is the server)
- Removed HegelMode enum and mode-related functions
- Renamed set_embedded_connection to set_connection
- SDK waits for hegeld to start and initiates version negotiation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add request_json() method that serializes serde_json::Value directly to CBOR
- Remove json_to_cbor/cbor_to_json manual conversion functions
- Remove base64_encode helper
- Update callers to use serde directly

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Close connection before child.wait() to prevent deadlock
- Use BigInt for u64 values > 2^53 to preserve precision
- Fix tautological comparisons in integers_bounds.rs
- Move test module to end of file in binary.rs

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove clone_for_embedded() - generators and mark_complete now share
  the same channel instance and message ID sequence
- Add TEST_ABORTED flag to track when StopTest occurs
- Skip sending mark_complete after StopTest since server closes channel
- Move mark_complete sending inside run_test_case to use same channel

This fixes tests that were hanging for 30 seconds when StopTest
occurred during generation.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Dependencies require Rust 1.81 or newer.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The SDK was conflating the control channel and test channel, sending
test_case/test_done events on the control channel instead of a
dedicated test channel. This updates the protocol flow to match the
Python SDK:

- Create a client-side test channel (odd IDs: 3, 5, 7...) for
  test_case/test_done events, separate from the control channel
- Send run_test with the test channel ID and wait for response
  immediately on the control channel
- Ack test_case events before running the test to prevent deadlock
- Process final replay test cases after test_done
- Send mark_complete as fire-and-forget (server sends no response)
- Close test case channels after mark_complete
- Use string format for origin field ("Panic at file.rs:42:1")

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@DRMacIver DRMacIver force-pushed the DRMacIver/new-protocol branch from 2a755cd to 8c082dd Compare February 5, 2026 14:11
- Include error type in protocol error messages so StopTest is detected
  instead of calling process::exit(134)
- Change mark_complete to request-response to prevent race condition
  when closing channels
- Remove unused send_request_json method
- Update Cargo.lock files to include ciborium and crc32fast
- Point flake.nix hegel input to DRMacIver/new-protocol branch
- Fix clippy warnings (div_ceil, io_other_error, manual_range_contains)
- Run cargo fmt and rustfmt on all source files

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@DRMacIver DRMacIver force-pushed the DRMacIver/new-protocol branch from 8c082dd to bb82cfb Compare February 5, 2026 14:45
DRMacIver and others added 8 commits February 5, 2026 15:47
CBOR natively supports NaN/infinity floats, but deserializing directly
to serde_json::Value silently converts them to null. Add cbor_to_json()
conversion that wraps these as {"$float": "nan"/"inf"/"-inf"} objects,
which HegelValue already knows how to decode.

Also fix conformance test to always pass allow_nan/allow_infinity params
instead of only setting them when true.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Prefix unused error variable with _ in socket connection retry loop.
The warning was appearing in stderr output, causing test_output tests
to fail because they expect stderr to start with the panic message.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use wrapping_mul instead of * to avoid overflow panics when hegel
generates large i32 values like 2^30.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The file contains the test runner (Hegel builder, subprocess spawning,
test case handling), not embedded mode logic. The old name was a
holdover from when hegel called the binary rather than vice versa.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove unused TEST_FAILURE exit code constant
- Remove unused negotiate_version() function (version negotiation
  is done inline in runner.rs)
- Remove unnecessary #[allow(dead_code)] on Connection::close()
  (it is used in runner.rs)
- Remove unnecessary #[allow(dead_code)] on DefaultGenerator trait
  (it's pub and used by derive macros)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace serde_json::Value with ciborium::Value as the native value type
throughout the SDK. This removes the serde_json dependency, preserves
NaN/Infinity natively (no wrapper objects needed), and eliminates the
cbor_to_json conversion shim.

Key changes:
- New src/cbor_helpers.rs with cbor_map!/cbor_array! macros and helpers
- protocol.rs: request_json() renamed to request_cbor(), removed cbor_to_json()
- gen/value.rs: From<ciborium::Value> replaces From<serde_json::Value>
- All generator files use cbor_map!/cbor_array! instead of json!
- hegel-derive generates ciborium::Value code directly
- runner.rs: all protocol messages use ciborium::Value
- Added 120s socket read timeout to prevent hangs on server errors
- Added display_value() for human-readable ciborium::Value formatting

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
DRMacIver and others added 3 commits February 6, 2026 10:57
The new protocol and UnsatisfiedAssumption fix are now merged to main.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@DRMacIver DRMacIver force-pushed the DRMacIver/new-protocol branch from 8099842 to 2023b0e Compare February 6, 2026 11:41
@DRMacIver
Copy link
Copy Markdown
Member Author

I'm also going to declare this one good enough to be worth merging. Definitely could use further improvements, but I think those should come in later pull requests and right now waiting for further improvements is worse than having this in main.

@DRMacIver DRMacIver merged commit 3213504 into main Feb 6, 2026
9 checks passed
@DRMacIver DRMacIver deleted the DRMacIver/new-protocol branch February 6, 2026 13:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants